home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / SOURCES / BUTTON.C < prev    next >
C/C++ Source or Header  |  1991-12-21  |  15KB  |  669 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * Button management.
  25.  */
  26.  
  27. #ifdef _3D
  28. #include <InterViews/color.h>
  29. #endif
  30.  
  31. #include <InterViews/bitmap.h>
  32. #include <InterViews/button.h>
  33. #include <InterViews/font.h>
  34. #include <InterViews/painter.h>
  35. #include <InterViews/pattern.h>
  36. #include <InterViews/sensor.h>
  37. #include <InterViews/shape.h>
  38. #include <InterViews/subject.h>
  39.  
  40. #include <InterViews/Bitmaps/radiob.bm>
  41. #include <InterViews/Bitmaps/radioc.bm>
  42. #include <InterViews/Bitmaps/radioh.bm>
  43. #include <InterViews/Bitmaps/radiom.bm>
  44. #include <InterViews/Bitmaps/radio.bm>
  45.  
  46. static const int sep = 3;
  47. static const int pad = 4;
  48.  
  49. inline int HalfRadioButtonSize (int h) { return round(.4*h); }
  50. inline int HalfCheckBoxSize (int h) { return round(.4*h); }
  51.  
  52. /*
  53.  * A button state is a value that is settable from one or more buttons.
  54.  * When the state is modified, it updates all its buttons.
  55.  */
  56.  
  57. ButtonState::ButtonState () {
  58.     value = nil;
  59.     Reference();
  60. }
  61.  
  62. ButtonState::ButtonState (int v) {
  63.     value = (void*)v;
  64.     Reference();
  65. }
  66.  
  67. ButtonState::ButtonState (void* v) {
  68.     value = v;
  69.     Reference();
  70. }
  71.  
  72. void ButtonState::SetValue (int v) {
  73.     Modify((void*)v);
  74. }
  75.  
  76. void ButtonState::SetValue (void* v) {
  77.     Modify(v);
  78. }
  79.  
  80. void ButtonState::operator= (ButtonState& s) {
  81.     Modify(s.value);
  82. }
  83.  
  84. void ButtonState::Modify (void* v) {
  85.     if (value != v) {
  86.     value = v;
  87.     Notify();
  88.     }
  89. }
  90.  
  91. /*
  92.  * Simple list of buttons.
  93.  */
  94.  
  95. class ButtonList {
  96. public:
  97.     Button* cur;
  98.     ButtonList* next;
  99.  
  100.     ButtonList (Button* b) { cur = b; next = nil; }
  101. };
  102.  
  103. static void Remove (ButtonList*& blist, Button* b) {
  104.     register ButtonList* bl;
  105.     register ButtonList* prev;
  106.  
  107.     prev = nil;
  108.     for (bl = blist; bl != nil; bl = bl->next) {
  109.     if (bl->cur == b) {
  110.         if (prev == nil) {
  111.         blist = bl->next;
  112.         } else {
  113.         prev->next = bl->next;
  114.         }
  115.         delete bl;
  116.         break;
  117.     }
  118.     prev = bl;
  119.     }
  120. }
  121.  
  122. static void DeleteList (ButtonList* blist) {
  123.     register ButtonList* bl;
  124.     register ButtonList* next;
  125.  
  126.     for (bl = blist; bl != nil; bl = next) {
  127.     next = bl->next;
  128.     delete bl;
  129.     }
  130. }
  131.  
  132. /*
  133.  * A button has a ButtonState subject that it modifies when pressed.
  134.  * Also, a button may have associated buttons that are enabled/disabled
  135.  * when it is chosen/unchosen.
  136.  */
  137.  
  138. Button::Button (ButtonState* s, void* v) {
  139.     Init(s, v);
  140. }
  141.  
  142. Button::Button (const char* name, ButtonState* s, void* v) {
  143.     SetInstance(name);
  144.     Init(s, v);
  145. }
  146.  
  147. Button::Button (Painter* out, ButtonState* s, void* v) : (nil, out) {
  148.     Init(s, v);
  149. }
  150.  
  151. void Button::Init (ButtonState* s, void* v) {
  152.     SetClassName("Button");
  153.     value = v;
  154.     subject = s;
  155.     associates = nil;
  156.     enabled = true;
  157.     hit = false;
  158.     subject->Attach(this);
  159.     Update();
  160.     input = new Sensor(updownEvents);
  161.     input->Catch(EnterEvent);
  162.     input->Catch(LeaveEvent);
  163. }
  164.  
  165. Button::~Button () {
  166.     if (subject != nil) {
  167.     subject->Detach(this);
  168.     }
  169.     DeleteList(associates);
  170. }
  171.  
  172. void Button::Attach (Button* b) {
  173.     ButtonList* head;
  174.  
  175.     head = new ButtonList(b);
  176.     head->next = associates;
  177.     associates = head;
  178.     if (chosen) {
  179.     b->Enable();
  180.     } else {
  181.     b->Disable();
  182.     }
  183. }
  184.  
  185. void Button::Detach (Button* b) {
  186.     Remove(associates, b);
  187. }
  188.  
  189. void Button::Enable () {
  190.     if (!enabled) {
  191.     enabled = true;
  192.     if (canvas != nil) {
  193.         Draw();
  194.     }
  195.     }
  196. }
  197.  
  198. void Button::Disable () {
  199.     if (enabled) {
  200.     enabled = false;
  201.     if (canvas != nil) {
  202.         Draw();
  203.     }
  204.     }
  205. }
  206.  
  207. void Button::Choose () {
  208.     register ButtonList* bl;
  209.  
  210.     if (!chosen) {
  211.     chosen = true;
  212.     if (enabled) {
  213.         if (canvas != nil) {
  214.         Refresh();
  215.         }
  216.         for (bl = associates; bl != nil; bl = bl->next) {
  217.         bl->cur->Enable();
  218.         }
  219.     }
  220.     }
  221. }
  222.  
  223. void Button::UnChoose () {
  224.     register ButtonList* bl;
  225.  
  226.     if (chosen) {
  227.     chosen = false;
  228.     if (enabled) {
  229.         if (canvas != nil) {
  230.         Refresh();
  231.         }
  232.         for (bl = associates; bl != nil; bl = bl->next) {
  233.         bl->cur->Disable();
  234.         }
  235.     }
  236.     }
  237. }
  238.  
  239. void Button::SetDimensions (int width, int height) {
  240.     shape->width = width;
  241.     shape->height = height;
  242.     shape->Rigid();
  243. }
  244.  
  245. void Button::Refresh () {
  246.     /* default shouldn't happen */
  247. }
  248.  
  249. void Button::Handle (register Event& e) {
  250.     if (e.eventType == DownEvent && e.target == this) {
  251.     boolean inside = true;
  252.     do {
  253.         if (enabled && e.target == this) {
  254.         if (e.eventType == EnterEvent) {
  255.             inside = true;
  256.         } else if (e.eventType == LeaveEvent) {
  257.             inside = false;
  258.         }
  259.         if (inside) {
  260.             if (!hit) {
  261.             hit = true;
  262.             Refresh();
  263.             }
  264.         } else {
  265.             if (hit) {
  266.             hit = false;
  267.             Refresh();
  268.             }
  269.         }
  270.         }
  271.         Read(e);
  272.     } while (e.eventType != UpEvent);
  273.     if (hit) {
  274.         hit = false;
  275.         Refresh();
  276.     }
  277.     if (enabled && inside) {
  278.         Press();
  279.     }
  280.     }
  281. }
  282.  
  283. void Button::Press () {
  284.     if (subject != nil) {
  285.     subject->SetValue(value);
  286.     } else {
  287.     Refresh();
  288.     }
  289. }
  290.  
  291. void Button::Update () {
  292.     void* v;
  293.  
  294.     subject->GetValue(v);
  295.     if (!chosen && value == v) {
  296.     Choose();
  297.     } else if (chosen && value != v) {
  298.     UnChoose();
  299.     }
  300. }
  301.  
  302. TextButton::TextButton (const char* str, ButtonState* s, void* v) : (s, v) {
  303.     Init(str);
  304. }
  305.  
  306. TextButton::TextButton (
  307.     const char* name, const char* str, ButtonState* s, void* v
  308. ) : (name, s, v) {
  309.     Init(str);
  310. }
  311.  
  312. TextButton::TextButton (
  313.     const char* str, ButtonState* s, void* v, Painter* out
  314. ) : (out, s, v) {
  315.     Init(str);
  316. }
  317.  
  318. void TextButton::Init (const char* str) {
  319.     SetClassName("TextButton");
  320.     text = str;
  321.     background = nil;
  322.     grayout = nil; }
  323.  
  324. void TextButton::MakeBackground () {
  325.     Unref(background);
  326.     background = new Painter(output);
  327.     background->Reference();
  328.     background->SetColors(output->GetBgColor(), output->GetFgColor());
  329.  
  330.     Unref(grayout);
  331.     grayout = new Painter(background);
  332.     grayout->Reference();
  333.     grayout->SetPattern(gray);
  334.     grayout->FillBg(false);
  335. }
  336.  
  337. void TextButton::MakeShape () {
  338.     if (text != nil) {
  339.     Font* f = output->GetFont();
  340.     shape->width += f->Width(text);
  341.     shape->height += f->Height();
  342.     }
  343.     shape->Rigid();
  344. }
  345.  
  346. TextButton::~TextButton () {
  347.     Unref(background);
  348.     Unref(grayout);
  349. }
  350.  
  351. PushButton::PushButton (
  352.     const char* str, ButtonState* s, int v
  353. ) : (str, s, (void*)v) {
  354.     Init();
  355. }
  356.  
  357. PushButton::PushButton (
  358.     const char* str, ButtonState* s, void* v
  359. ) : (str, s, v) {
  360.     Init();
  361. }
  362.  
  363. PushButton::PushButton (
  364.     const char* name, const char* str, ButtonState* s, int v
  365. ) : (name, str, s, (void*)v) {
  366.     Init();
  367. }
  368.     
  369. PushButton::PushButton (
  370.     const char* name, const char* str, ButtonState* s, void* v
  371. ) : (name, str, s, v) {
  372.     Init();
  373. }
  374.  
  375. PushButton::PushButton (
  376.     const char* str, ButtonState* s, int v, Painter* out
  377. ) : (str, s, (void*)v, out) {
  378.     Init();
  379. }
  380.  
  381. PushButton::PushButton (
  382.     const char* str, ButtonState* s, void* v, Painter* out
  383. ) : (str, s, v, out) {
  384.     Init();
  385. }
  386.  
  387. void PushButton::Init () {
  388.     SetClassName("PushButton");
  389. }
  390.  
  391. void PushButton::Reconfig () {
  392.     MakeBackground();
  393.     if (shape->Undefined()) {
  394.     MakeShape();
  395.     shape->width += output->GetFont()->Width("    ");
  396.     shape->height += 2*pad;
  397.     }
  398. }
  399.  
  400. void PushButton::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
  401.     output->ClearRect(canvas, x1, y1, x2, y2);
  402.     Refresh();
  403. }
  404.  
  405. void PushButton::Refresh () {
  406.  
  407.   #ifndef _3D
  408.     register int r;
  409.     Coord x[16], y[16];
  410.     Coord tx, ty;
  411.  
  412.     r = min(10*pixels, min(xmax+1, ymax+1)/6);
  413.     x[0] = 0; y[0] = r;
  414.     x[1] = 0; y[1] = r + r;
  415.     x[2] = 0; y[2] = ymax - r - r;
  416.     x[3] = 0; y[3] = ymax - r;
  417.     x[4] = r; y[4] = ymax;
  418.     x[5] = r + r; y[5] = ymax;
  419.     x[6] = xmax - r - r; y[6] = ymax;
  420.     x[7] = xmax - r; y[7] = ymax;
  421.     x[8] = xmax; y[8] = ymax - r;
  422.     x[9] = xmax; y[9] = ymax - r - r;
  423.     x[10] = xmax; y[10] = r + r;
  424.     x[11] = xmax; y[11] = r;
  425.     x[12] = xmax - r; y[12] = 0;
  426.     x[13] = xmax - r - r; y[13] = 0;
  427.     x[14] = r + r; y[14] = 0;
  428.     x[15] = r; y[15] = 0;
  429.     tx = (xmax - output->GetFont()->Width(text))/2;
  430.     ty = pad;
  431.     if (chosen || hit) {
  432.     output->FillBSpline(canvas, x, y, 16); 
  433.     background->Text(canvas, text, tx, ty);
  434.     } else {
  435.     background->FillRect(canvas, 0, 0, xmax, ymax);
  436.     output->ClosedBSpline(canvas, x, y, 16);
  437.     output->Text(canvas, text, tx, ty);
  438.     }
  439.     if (!enabled) {
  440.     grayout->FillRect(canvas, 0, 0, xmax, ymax);
  441.     }
  442.   #endif
  443.   #ifdef _3D
  444.     Coord tx, ty;
  445.     
  446.     tx = (xmax - output3D->GetFont()->Width(text))/2;
  447.     ty = pad;
  448.  
  449.    if (chosen || hit) // Button wurde gedrueckt
  450.    { output3D->Border(canvas,false);
  451.      output3D->InvertColors();
  452.      output3D->FillRect(canvas,2,2,xmax-2,ymax-2);
  453.      output3D->InvertColors(); 
  454.      output->Text(canvas, text, tx+1, ty+1); }
  455.    else 
  456.    { output3D->Border(canvas); 
  457.      output->Text(canvas, text, tx, ty); } 
  458.    if (!enabled) 
  459.     { grayout->FillRect(canvas, 0, 0, xmax, ymax); }
  460.   #endif  
  461. }
  462.  
  463. static Bitmap* radioMask;
  464. static Bitmap* radioPlain;
  465. static Bitmap* radioHit;
  466. static Bitmap* radioChosen;
  467. static Bitmap* radioBoth;
  468.  
  469. RadioButton::RadioButton (
  470.     const char* str, ButtonState* s, int v
  471. ) : (str, s, (void*)v) {
  472.     Init();
  473. }
  474.  
  475. RadioButton::RadioButton (
  476.     const char* str, ButtonState* s, void* v
  477. ) : (str, s, v) {
  478.     Init();
  479. }
  480.  
  481. RadioButton::RadioButton (
  482.     const char* name, const char* str, ButtonState* s, int v
  483. ) : (name, str, s, (void*)v) {
  484.     Init();
  485. }
  486.  
  487. RadioButton::RadioButton (
  488.     const char* name, const char* str, ButtonState* s, void* v
  489. ) : (name, str, s, v) {
  490.     Init();
  491. }
  492.  
  493. RadioButton::RadioButton (
  494.     const char* str, ButtonState* s, int v, Painter* out
  495. ) : (str, s, (void*)v, out) {
  496.     Init();
  497. }
  498.  
  499. RadioButton::RadioButton (
  500.     const char* str, ButtonState* s, void* v, Painter* out
  501. ) : (str, s, v, out) {
  502.     Init();
  503. }
  504.  
  505. void RadioButton::Init () {
  506.     SetClassName("RadioButton");
  507. }
  508.  
  509. void RadioButton::Reconfig () {
  510.     MakeBackground();
  511.     if (shape->Undefined()) {
  512.     MakeShape();
  513.     shape->width += shape->height + sep;
  514.     }
  515.     if (radioMask == nil) {
  516.         radioMask = new Bitmap(
  517.             radio_mask_bits, radio_mask_width, radio_mask_height
  518.         );
  519.     radioMask->Reference();
  520.         radioPlain = new Bitmap(
  521.             radio_plain_bits, radio_plain_width, radio_plain_height
  522.         );
  523.     radioPlain->Reference();
  524.         radioHit = new Bitmap(
  525.             radio_hit_bits, radio_hit_width, radio_hit_height
  526.         );
  527.     radioHit->Reference();
  528.         radioChosen = new Bitmap(
  529.             radio_chosen_bits, radio_chosen_width, radio_chosen_height
  530.         );
  531.     radioChosen->Reference();
  532.         radioBoth = new Bitmap(
  533.             radio_both_bits, radio_both_width, radio_both_height
  534.         );
  535.     radioBoth->Reference();
  536.     }
  537. }
  538.  
  539. void RadioButton::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
  540.     int h = output->GetFont()->Height();
  541.     int r = radio_plain_width;
  542.     output->ClearRect(canvas, x1, y1, x2, y2);
  543.     Coord tx = r + sep;
  544.     Coord ty = (ymax + 1 - h) / 2;
  545.     output->Text(canvas, text, tx, ty);
  546.     Refresh();
  547. }
  548.  
  549. void RadioButton::Refresh () {
  550.     Coord x = 0;
  551.     Coord y = (ymax+1 - radio_plain_height)/2;
  552.     if (!hit && !chosen) {
  553.         output->Stencil(canvas, x, y, radioPlain, radioMask);
  554.     } else if (hit && !chosen) {
  555.         output->Stencil(canvas, x, y, radioHit, radioMask);
  556.     } else if (!hit && chosen) {
  557.         output->Stencil(canvas, x, y, radioChosen, radioMask);
  558.     } else if (hit && chosen) {
  559.         output->Stencil(canvas, x, y, radioBoth, radioMask);
  560.     }
  561.     if (!enabled) {
  562.     grayout->FillRect(canvas, 0, 0, xmax, ymax);
  563.     }
  564. }
  565.  
  566. CheckBox::CheckBox (
  567.     const char* str, ButtonState* s, int on, int off
  568. ) : (str, s, (void*)on) {
  569.     Init((void*)off);
  570. }
  571.  
  572. CheckBox::CheckBox (
  573.     const char* str, ButtonState* s, void* on, void* off
  574. ) : (str, s, on) {
  575.     Init(off);
  576. }
  577.  
  578. CheckBox::CheckBox (
  579.     const char* name, const char* str, ButtonState* s, int on, int off
  580. ) : (name, str, s, (void*)on) {
  581.     Init((void*)off);
  582. }
  583.  
  584. CheckBox::CheckBox (
  585.     const char* name, const char* str, ButtonState* s, void* on, void* off
  586. ) : (name, str, s, on) {
  587.     Init(off);
  588. }
  589.  
  590. CheckBox::CheckBox (
  591.     const char* str, ButtonState* s, int on, int off, Painter* out
  592. ) : (str, s, (void*)on, out) {
  593.     Init((void*)off);
  594. }
  595.  
  596. CheckBox::CheckBox (
  597.     const char* str, ButtonState* s, void* on, void* off, Painter* out
  598. ) : (str, s, on, out) {
  599.     Init(off);
  600. }
  601.  
  602. void CheckBox::Init (void* v) {
  603.     SetClassName("CheckBox");
  604.     offvalue = v;
  605. }
  606.  
  607. void CheckBox::Reconfig () {
  608.     MakeBackground();
  609.     if (shape->Undefined()) {
  610.     MakeShape();
  611.     shape->width += shape->height + sep;
  612.     }
  613.     Update();
  614. }
  615.  
  616. void CheckBox::Press () {
  617.     if (chosen) {
  618.     subject->GetValue(value);
  619.     subject->SetValue(offvalue);
  620.     } else {
  621.     subject->SetValue(value);
  622.     }
  623. }
  624.  
  625. void CheckBox::Update () {
  626.     void* v;
  627.  
  628.     subject->GetValue(v);
  629.     if (v != offvalue) {
  630.     Choose();
  631.     value = v;
  632.     } else {
  633.     UnChoose();
  634.     }
  635. }
  636.  
  637. void CheckBox::Redraw (Coord x1, Coord y1, Coord x2, Coord y2) {
  638.     int h = output->GetFont()->Height();
  639.     int t = HalfCheckBoxSize(h);
  640.     output->ClearRect(canvas, x1, y1, x2, y2);
  641.     Coord tx = 2*t + sep;
  642.     Coord ty = (ymax + 1 - h) / 2;
  643.     output->Text(canvas, text, tx, ty);
  644.     Refresh();
  645. }
  646.  
  647. void CheckBox::Refresh () {
  648.     int h = output->GetFont()->Height();
  649.     int t = HalfCheckBoxSize(h);
  650.     Coord cx = t;
  651.     Coord cy = (ymax + 1)/2;
  652.     Coord left = cx - t;
  653.     Coord right = cx + t;
  654.     Coord bottom = cy - t;
  655.     Coord top = cy + t;
  656.     output->Rect(canvas, left, bottom, right, top);
  657.     background->FillRect(canvas, left+1, bottom+1, right-1, top-1);
  658.     if (hit) {
  659.     output->Rect(canvas, left+1, bottom+1, right-1, top-1);
  660.     }
  661.     if (chosen) {
  662.     output->Line(canvas, left, bottom, right, top);
  663.     output->Line(canvas, left, top, right, bottom);
  664.     }
  665.     if (!enabled) {
  666.     grayout->FillRect(canvas, 0, 0, xmax, ymax);
  667.     }
  668. }
  669.